package org.dmikis.task11.engine;

import static java.lang.Math.cos;
import static java.lang.Math.sin;

import java.util.ArrayList;

import org.dmikis.task11.PhasePoint;
import org.dmikis.task11.parameter.AbstractParameter;


public class BasicEngine implements Engine {
    
    protected BasicEngine() {
	this.points = new ArrayList<PhasePoint>();
	this.parameters = new ArrayList<AbstractParameter>(3);
    }
    
    public static Engine getInstance() {
	return engine;
    }

    @Override
    public void run() {
	_isRunning = true;
	for (double currentTime = 0.0; currentTime <= 1.0; currentTime += TIME_STEP) {
	    state = (byte) (100.0 * currentTime);
	    PhasePoint currentPoint = points.get(points.size() - 1);
	    double dV = -sin(currentPoint.getTetta()) - A*currentPoint.getV()*currentPoint.getV();
	    double dTetta = currentPoint.getV() - cos(currentPoint.getTetta()) / currentPoint.getV();
	    points.add(new PhasePoint(currentPoint.getV()+dV*TIME_STEP, currentPoint.getTetta() + dTetta*TIME_STEP, currentPoint.getT() + TIME_STEP));
	}
	_isRunning = false;
    }

    @Override
    public void setStartingPoint(PhasePoint p) {
	points.clear();
	points.add(p);
    }

    @Override
    public void setErrorValue(double e) {
	// TODO Auto-generated method stub
    }
    
    @Override
    public double getTimeStep() {
	return TIME_STEP;
    }

    @Override
    public PhasePoint getPoint(double t) {
	for (PhasePoint p : points) {
	    if (p.getT() == t) {
		return p;
	    }
	}
	return null;
    }

    @Override
    public double[] getTimeline() {
	double[] timeline = new double[points.size()];
	int c = 0;
	for (PhasePoint p : points) {
	    timeline[c++] = p.getT();
	}
	return timeline;
    }
    
    @Override
    public byte getState() {
	return _isRunning ? state : -1;
    }
    
    @Override
    public ArrayList<AbstractParameter> getEngineParameters() {
	return this.parameters;
    }
    
    protected volatile byte state = 0;
    protected volatile boolean _isRunning = false;
    
    protected static Engine engine = new BasicEngine();
    protected ArrayList<PhasePoint> points;
    protected ArrayList<AbstractParameter> parameters;
    
    protected static final double TIME_STEP = 0.01;
    protected static final double A = 0.00001;

}
